<template>
    <div class="lazy-image" :class="{ loading: isLoading, error: hasError }">
        <img v-if="shouldLoad && !hasError" :src="currentSrc" :alt="alt" :class="imageClass" @load="onLoad"
            @error="onError" />

        <!-- 加载占位符 -->
        <div v-if="isLoading" class="placeholder">
            <div class="placeholder-content">
                <van-loading size="20px" />
                <span v-if="showLoadingText">加载中...</span>
            </div>
        </div>

        <!-- 错误占位符 -->
        <div v-if="hasError" class="error-placeholder">
            <van-icon name="photo-fail" size="24" />
            <span v-if="showErrorText">加载失败</span>
            <button v-if="allowRetry" @click="retry" class="retry-btn">
                重试
            </button>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'

// Props
interface Props {
    src: string
    alt?: string
    placeholder?: string
    fallback?: string
    lazy?: boolean
    threshold?: number
    imageClass?: string
    showLoadingText?: boolean
    showErrorText?: boolean
    allowRetry?: boolean
    quality?: 'low' | 'medium' | 'high'
}

const props = withDefaults(defineProps<Props>(), {
    alt: '',
    placeholder: '',
    fallback: '',
    lazy: true,
    threshold: 0.1,
    imageClass: '',
    showLoadingText: false,
    showErrorText: true,
    allowRetry: true,
    quality: 'medium'
})

// Emits
const emit = defineEmits<{
    load: [event: Event]
    error: [event: Event]
    visible: []
}>()

// 响应式数据
const isLoading = ref(true)
const hasError = ref(false)
const shouldLoad = ref(!props.lazy)
const retryCount = ref(0)
const imageRef = ref<HTMLElement>()

// 计算属性
const currentSrc = computed(() => {
    if (hasError.value && props.fallback) {
        return props.fallback
    }

    // 根据质量设置调整图片URL
    if (props.src.includes('?')) {
        return `${props.src}&q=${getQualityValue()}`
    } else {
        return `${props.src}?q=${getQualityValue()}`
    }
})

// 方法
const getQualityValue = () => {
    switch (props.quality) {
        case 'low': return '50'
        case 'medium': return '75'
        case 'high': return '90'
        default: return '75'
    }
}

const onLoad = (event: Event) => {
    isLoading.value = false
    hasError.value = false
    emit('load', event)
}

const onError = (event: Event) => {
    isLoading.value = false
    hasError.value = true
    emit('error', event)
}

const retry = () => {
    if (retryCount.value < 3) {
        retryCount.value++
        isLoading.value = true
        hasError.value = false

        // 强制重新加载图片
        const img = new Image()
        img.onload = () => {
            isLoading.value = false
            hasError.value = false
        }
        img.onerror = () => {
            isLoading.value = false
            hasError.value = true
        }
        img.src = props.src + '?retry=' + retryCount.value
    }
}

// 懒加载逻辑
let observer: IntersectionObserver | null = null

const setupLazyLoading = () => {
    if (!props.lazy || !imageRef.value) return

    observer = new IntersectionObserver(
        (entries) => {
            entries.forEach((entry) => {
                if (entry.isIntersecting) {
                    shouldLoad.value = true
                    emit('visible')
                    observer?.unobserve(entry.target)
                }
            })
        },
        {
            threshold: props.threshold,
            rootMargin: '50px'
        }
    )

    observer.observe(imageRef.value)
}

// 预加载逻辑
const preloadImage = () => {
    if (!shouldLoad.value) return

    const img = new Image()
    img.onload = () => {
        isLoading.value = false
    }
    img.onerror = () => {
        hasError.value = true
        isLoading.value = false
    }
    img.src = currentSrc.value
}

// 生命周期
onMounted(() => {
    if (props.lazy) {
        setupLazyLoading()
    } else {
        preloadImage()
    }
})

onUnmounted(() => {
    if (observer) {
        observer.disconnect()
    }
})

// 监听shouldLoad变化
import { watch } from 'vue'
watch(shouldLoad, (newValue) => {
    if (newValue) {
        preloadImage()
    }
})
</script>

<style lang="scss" scoped>
.lazy-image {
    position: relative;
    display: inline-block;
    overflow: hidden;
    background: #f5f5f5;

    img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        transition: opacity 0.3s ease;
    }

    .placeholder,
    .error-placeholder {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        background: #f8f9fa;
        color: #6c757d;
    }

    .placeholder {
        .placeholder-content {
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 8px;

            span {
                font-size: 12px;
            }
        }
    }

    .error-placeholder {
        gap: 8px;

        span {
            font-size: 12px;
        }

        .retry-btn {
            background: #007bff;
            color: white;
            border: none;
            padding: 4px 12px;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            margin-top: 8px;

            &:hover {
                background: #0056b3;
            }
        }
    }

    &.loading {
        .placeholder {
            opacity: 1;
        }
    }

    &.error {
        .error-placeholder {
            opacity: 1;
        }
    }
}

// 响应式设计
@media (max-width: 768px) {
    .lazy-image {

        .placeholder,
        .error-placeholder {
            font-size: 11px;
        }
    }
}
</style>